﻿// -----------------------------------------------------------------------
// <copyright file="PushStatsBatchUpdaterService.cs" company="Zen Design Corp">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Zen.BlackBerry.Push.Stats
{
	using System.Collections.Generic;
	using System.Linq;
	using System.Threading;
	using Microsoft.Practices.Unity;

	/// <summary>
	/// Implementation of the <see cref="IPushStatsBatchUpdaterService"/>
	/// interface.
	/// </summary>
	public class PushStatsBatchUpdaterService : IPushStatsBatchUpdaterService
	{
		private SemaphoreSlim _queueLock = new SemaphoreSlim(1, 1);
		private List<PushStats> _queue = new List<PushStats>();

		/// <summary>
		/// Initializes a new instance of the <see cref="PushStatsBatchUpdaterService"/> class.
		/// </summary>
		public PushStatsBatchUpdaterService()
		{
		}

		/// <summary>
		/// Gets or sets the repository.
		/// </summary>
		/// <value>The repository.</value>
		[Dependency]
		public IPushStatsRepository Repository
		{
			get;
			set;
		}

		#region IPushStatsBatchUpdaterService Members

		/// <summary>
		/// Returns the size of the queue holding push stats waiting to be
		/// batched and processed.
		/// </summary>
		/// <value>The size of the push stats queue.</value>
		public int PushStatsQueueSize
		{
			get
			{
				return _queue.Count;
			}
		}

		/// <summary>
		/// Adds a push stats object to the list of updates to be batched.
		/// </summary>
		/// <param name="pushStats">The push stats.</param>
		public void AddPushStatsUpdate(PushStats pushStats)
		{
			Repository.UpdateCache(pushStats);
			_queueLock.Wait();
			try
			{
				_queue.Add(pushStats);
			}
			finally
			{
				_queueLock.Release();
			}
		}

		/// <summary>
		/// When a reset is called, find all push stats objects in the list of
		/// updates and set their contribution to the running content sum to 0.
		/// </summary>
		/// <param name="applicationId">The application id.</param>
		public void ResetRunningContentSum(string applicationId)
		{
			_queueLock.Wait();
			try
			{
				foreach (PushStats stats in _queue.Where((item) =>
					item.ApplicationId == applicationId))
				{
					stats.RunningContentSum = 0;
				}
			}
			finally
			{
				_queueLock.Release();
			}
		}

		/// <summary>
		/// When a reset is called, find all push stats objects in the list of
		/// updates and set their contribution to the running push count to 0.
		/// </summary>
		/// <param name="applicationId">The application id.</param>
		public void ResetRunningPushCount(string applicationId)
		{
			_queueLock.Wait();
			try
			{
				foreach (PushStats stats in _queue.Where((item) =>
					item.ApplicationId == applicationId))
				{
					stats.RunningPushCount = 0;
				}
			}
			finally
			{
				_queueLock.Release();
			}
		}

		/// <summary>
		/// Performs a batch update of several push stats objects to storage.
		/// </summary>
		public void Run()
		{
			// Replace the stat update queue
			List<PushStats> updates = null;
			_queueLock.Wait();
			try
			{
				updates = _queue;
				_queue = new List<PushStats>();
			}
			finally
			{
				_queueLock.Release();
			}

			// Pass update list to repository
			Repository.BatchUpdatePushStats(updates.AsReadOnly());
		}

		#endregion
	}
}
